//
//  ViewController.swift
//  AsyncAwait
//
//  Created by admin on 2021/10/27.
//

import UIKit

class ViewController: UIViewController {
    
    var contination: CheckedContinuation<UIImage?, Never>?
    
    var imagesArray: [DetailedImage] = [DetailedImage]()

    @IBOutlet weak var imageButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
//        Task {
//            let detailImage = try await downloadImageAndMetadata(imageNumber: 1)
//            self.showImage(detailImage)
//        }
        
        
//        var detailImages = [DetailedImage]()
//        for  num in [1, 2, 3, 4] {
//            Task {
//                let detailImage = try await downloadImageAndMetadata(imageNumber: num)
//                detailImages.append(detailImage)
//            }
//        }
        
        Task {
            
            do {
                let images = try await downloadMultipleImagesWithMetadata(imageNumbers: [1,2,3,4])
            } catch ImageDownloadError.badImage {
                print("图片下载失败")
            }
            
            
        }
        
      
        setupUI()
        doOtherThing()
        
    }
    
    func setupUI(){
        print("初始化UI开始")
        sleep(1)
        print("初始化UI完成")
    }
    
    func doOtherThing(){
        print("其他事开始")
        print("其他事结束")
    }
    
    @MainActor
    func showImage(_ detailImage: DetailedImage){
        print("刷新UI")
        self.imageButton.setImage(detailImage.image, for: .normal)
    }
    
    //MARK: call back based
    func requestUserAgeBaseCallBack(_ completeHandler: @escaping (Int)->() ){
        NetworkManager<Int>.netWorkRequest("url") { response, error in
            completeHandler(response?.data ?? 0)
        }
    }
    
    
    
    
    
    
    
    
    
    func requestUserAgeAsyncAwait() async throws -> Int{
        return try await withCheckedThrowingContinuation({ (containuation: CheckedContinuation<Int, Error>) in
            NetworkManager<Int>.netWorkRequest("url") { response, error in
                if let age = response?.data {
                    containuation.resume(returning: age)
                }else {
                    containuation.resume(throwing: error!)
                }
            }
        })
    }

    
    //Mark: delegate based
    @MainActor
    @IBAction func selectImageAction(_ sender: UIButton) {

        Task {
            let pickerDelegate = ImagePickerDelegate()
           
            let image = try? await pickerDelegate.chooseImageFromPhotoLibrary()
            sender.setImage(image, for: .normal)
            
     
        }
    }
    
}

//MARK: -- Asnc Properties
extension UIImage {
    // only read-only properties can be async
    var thumbnail: UIImage? {
        get async {
            let size = CGSize(width: 40, height: 40)
            return await self.byPreparingThumbnail(ofSize: size)
        }
    }
}




//MARK: --- Async - let (Async 并发)
extension ViewController {
    func downloadImageAndMetadata(imageNumber: Int) async throws -> DetailedImage {


        print(">>>>>>>>>> 1 \(Thread.current)")
        async let image =  downloadImage(imageNumber: imageNumber)
        async let metadata =  downloadMetadata(for: imageNumber)
        
        print(">>>>>>>> 2 \(Thread.current)")
        
        let detailImage = DetailedImage(image: try await image, metadata: try await metadata)
        print(">>>>>>>> 3 \(Thread.current)")
        return detailImage
    }

    func downloadImage(imageNumber: Int) async throws -> UIImage {
        try Task.checkCancellation()
        
//        if Task.isCancelled {
//            throw ImageDownloadError.invalidMetadata
//        }
        
        print("downloadImage----- begin \(Thread.current)")
        
        let imageUrl = URL(string: "http://r1on82fmy.hn-bkt.clouddn.com/await\(imageNumber).jpeg")!
        let imageRequest = URLRequest(url: imageUrl)
        let (data, imageResponse) = try await URLSession.shared.data(for: imageRequest)
        print("downloadImage----- end ")
        guard let image = UIImage(data: data), (imageResponse as? HTTPURLResponse)?.statusCode == 200 else {
            throw ImageDownloadError.badImage
        }
    
        return image
    }

    func downloadMetadata(for id: Int) async throws -> ImageMetadata {
        
        try Task.checkCancellation()
        
//        if Task.isCancelled {
//            throw ImageDownloadError.invalidMetadata
//        }\
        print("downloadMetadata --- begin \(Thread.current)")
        let metadataUrl = URL(string: "http://r1ongpxur.hn-bkt.clouddn.com/imagemeta\(id).json")!
        let metadataRequest = URLRequest(url: metadataUrl)
        let (data, metadataResponse) = try await URLSession.shared.data(for: metadataRequest)

        print("downloadMetadata --- end  \(Thread.current)")
        guard (metadataResponse as? HTTPURLResponse)?.statusCode == 200 else {
            throw ImageDownloadError.invalidMetadata
        }

        return try JSONDecoder().decode(ImageMetadata.self, from: data)
    }
}

struct ImageMetadata: Codable {
    let name: String
    let firstAppearance: String
    let year: Int
}

struct DetailedImage {
    let image: UIImage
    let metadata: ImageMetadata
}

enum ImageDownloadError: Error {
    case badImage
    case invalidMetadata
}


// MARK --- Group Task
// 以上 在同一时间只能创建一个Task，
extension ViewController {
    
    // Mutation of captured var 'imagesMetadata' in concurrently-executing code
    func downloadMultipleImagesWithMetadata(imageNumbers: [Int]) async throws -> [DetailedImage]{
        var imagesMetadata: [DetailedImage] = []
   
        try await withThrowingTaskGroup(of: DetailedImage.self) { group in
            for imageNumber in imageNumbers {
                // 向Taskgroup中添加
                group.addTask(priority: .medium) {
                    async let image = self.downloadImageAndMetadata(imageNumber: imageNumber)
                    return try await image
                }
            }
            //等Task组里面的任务都执行完
            for try await imageDetail in group {
                imagesMetadata.append(imageDetail)

                Task.detached(priority: .low) {
                    await self.doSomeOtherImageHandler(imageDetail: imageDetail)
                }
            }
        }
        return imagesMetadata
    }
//    try await withThrowingTaskGroup(of: Void.self) { group in
//        for imageNumber in imageNumbers {
//            group.addTask(priority: .medium) {
//                async let image = self.downloadImageAndMetadata(imageNumber: imageNumber)
//                imagesMetadata.append(try await image)
//            }
//        }
//    }
    
    
    //        @Sendable
    //        Cannot capture mutable variables.
    //        You should only capture value types, actors, classes, or other objects that implement their own synchronization. We will explore actors in a future article.
            
            

}


extension ViewController {
    func doSomeOtherImageHandler(imageDetail: DetailedImage) async {
        

        await Task.sleep(4)
        print("other thing done !!!!!!! \(Thread.current)")
        
        
        
    }
}
